/* Copyright (c) 2001 IBK-Landquart-Switzerland. All rights reserved.
 *
 * Module      :  ZProfile.cpp
 * Application :  IBK Open Class Library
 * Purpose     :  Profile access
 *
 * Date        Description                                 Who
 * --------------------------------------------------------------------------
 * 2001.05.31  First implementation                        P.Koch, IBK
 *
 * OPEN SOURCE LICENSE
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to IBK at info@ibk-software.ch.
 */

#define ZC_BUILDING_ZBASE

#include <ZTrace.hpp>
#include <ZProfile.hpp>
#include <ZExcept.hpp>

#ifdef ZC_OS2

#define INCL_WINERRORS
#define INCL_SHLERRORS
#define INCL_WINSHELLDATA
#include <os2.h>

// sys messages

static const char Colon[] =                    ": ";
static const char PrfCloseProfileName[] =      "PrfCloseProfile";
static const char PrfOpenProfileName[] =       "PrfOpenProfile";
static const char PrfQueryProfileName[] =      "PrfQueryProfile";
static const char PrfQueryProfileDataName[] =  "PrfQueryProfileData";
static const char PrfQueryProfileIntName[] =   "PrfQueryProfileInt";
static const char PrfQueryProfileSizeName[] =  "PrfQueryProfileSize";
static const char PrfQueryProfileStringName[] ="PrfQueryProfileString";
static const char PrfResetName[] =             "PrfReset";
static const char PrfWriteProfileDataName[] =  "PrfWriteProfileData";
static const char PrfWriteProfileStringName[] ="PrfWriteProfileString";
static const char WinInitializeName[] =        "WinInitialize";

// other messages

static const char MissingPath[] =              "missing path";
static const char MissingValueName[] =         "missing value name";

#define throwSysErr(aFunction) ZTHROWEXC(ZString(aFunction)+Colon+getOs2Error())

ZString ZProfile::getOs2Error() const
{
   ZFUNCTRACE_DEVELOP("getOs2Error()");

   ZString msg;
   ERRORID err = WinGetLastError(iHab);
   switch (ERRORIDSEV(err)) {
      case 0x0000: msg = "No Error - "; break;
      case 0x0004: msg = "Warning - "; break;
      case 0x000C: msg = "Severe - "; break;
      case 0x0010: msg = "Unrecoverable - "; break;
      case 0x0008:
      default:     msg = "Error - "; break;
   } // switch
   switch (ERRORIDERROR(err)) {
      case 0x1124:
         msg += "User or system initialization file cannot be closed.";
         break;
      case 0x1115:
         msg += "An invalid initialization-file handle was specified.";
         break;
      case 0x1301:
         msg += "Unable to open initialization file.";
         break;
      case 0x1309:
         msg += "An error occurred during memory management.";
         break;
      case 0x1303:
         msg += "A parameter to the function contained invalid data.";
         break;
      case 0x1304:
         msg += "The application name, key name or program handle was not found.";
         break;
      case 0x110B:
         msg += "The supplied buffer was not large enough for the data.";
         break;
      case 0x130C:
         msg += "The profile string is not a valid zero-terminated string.";
         break;
      default:
         msg += ZString::hex(ERRORIDERROR(err));
   } // switch
   return msg;
} // getOs2Error

#endif // ZC_OS2

#ifdef ZC_WIN

#define NO_STRICT
#include <windows.h>

// string constants
static const char ValueNotFound[] =       "value not found";
static const char UnsupportedDataType[] = "unsupported data type";
static const char Software[] =            "Software";
static const char Colon[] =               ": ";

static const char SRegCreateKeyEx[] =     "RegCreateKeyEx";
static const char SRegOpenKeyEx[] =       "RegOpenKeyEx";
static const char SRegSetValueEx[] =      "RegSetValueEx";
static const char SRegQueryValueEx[] =    "RegQueryValueEx";

typedef struct { const char* iName; HKEY iHandle; } SystemHandle;

static SystemHandle sysHandles[] = {
    { "HKEY_LOCAL_MACHINE",    HKEY_LOCAL_MACHINE    }
   ,{ "HKEY_CURRENT_USER",     HKEY_CURRENT_USER     }
   ,{ "HKEY_CLASSES_ROOT",     HKEY_CLASSES_ROOT     }
   ,{ "HKEY_USERS",            HKEY_USERS            }
   ,{ "HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA }
#if (WINVER >= 0x0400)
   ,{ "HKEY_CURRENT_CONFIG",   HKEY_CURRENT_CONFIG   }
   ,{ "HKEY_DYN_DATA",         HKEY_DYN_DATA         }
#endif
}; // sysHandles

#define throwSysErr(aFunction) ZTHROWEXC(ZString(aFunction)+Colon+getWinError())

static ZString getWinError()
{
   ZFUNCTRACE_DEVELOP("getWinError()");

   DWORD errcode = GetLastError();
   LPTSTR lpMsgBuf;
   FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,
      errcode,
      MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
      (LPTSTR)&lpMsgBuf,
      0, NULL
   );
   ZString msg(lpMsgBuf);
   LocalFree(lpMsgBuf);
   return msg;
} // getWinError

static ZString splitPath(ZString& aPath)
{
   ZFUNCTRACE_DEVELOP("splitPath(ZString& aPath)");
   long pos(aPath.indexOf(ZC_PATHSEPARATOR));
   if (!pos) {
      ZString ret(aPath);
      aPath = "";
      return ret;
   } // if
   ZString ret(aPath.subString(1,pos-1));
   aPath = aPath.subString(pos+1);
   return ret;
} // splitPath

static ZString stripPath(const ZString& aPath)
{
   ZFUNCTRACE_DEVELOP("stripPath(const ZString& aPath)");
   ZString path(aPath);
   path.strip(ZC_PATHSEPARATOR);
   return path;
} // stripPath

static ZBoolean isSystemHandle(HKEY aHandle)
{
   ZFUNCTRACE_DEVELOP("isSystemHandle(HKEY aHandle)");
   for (unsigned i = 0; i < sizeof(sysHandles)/sizeof(SystemHandle); i++)
      if (aHandle == sysHandles[i].iHandle) return zTrue;
   return zFalse;
} // isSystemHandle

static void closeHandle(HKEY aHandle)
{
   ZFUNCTRACE_DEVELOP("closeHandle(HKEY aHandle)");
   if (!isSystemHandle(aHandle)) RegCloseKey(aHandle);
} // closeHandle

static HKEY openHandle(HKEY aParentHandle, ZString aPath, ZBoolean aCreate)
{
   ZFUNCTRACE_DEVELOP("openHandle(HKEY aParentHandle, ZString aPath, ZBoolean aCreate)");
   HKEY parentHandle(aParentHandle);
   HKEY handle;
   for (;;) {
      ZString token(splitPath(aPath));
      if (aCreate) {
         if (RegCreateKeyEx(
                parentHandle, token.constBuffer(), 0, "",
                REG_OPTION_NON_VOLATILE, (KEY_READ | KEY_WRITE),
                NULL, &handle, NULL) != ERROR_SUCCESS ) {
            if (parentHandle != aParentHandle) closeHandle(parentHandle);
            throwSysErr(SRegCreateKeyEx);
         } // if
      } else {
         if (RegOpenKeyEx(
                parentHandle, token.constBuffer(), 0,
                KEY_READ, &handle) != ERROR_SUCCESS) {
            if (parentHandle != aParentHandle) closeHandle(parentHandle);
            throwSysErr(SRegOpenKeyEx);
         } // if
      } // if
      if (parentHandle != aParentHandle) closeHandle(parentHandle);
      if (aPath.size() == 0) break;
      parentHandle = handle;
   } // for
   return handle;
} // openHandle

void ZProfile::openPath(ZBoolean aCreate)
{
   ZFUNCTRACE_DEVELOP("ZProfile::openPath(ZBoolean aCreate)");
   if (iPathHandle == 0 || (aCreate && iPathReadOnly)) {
      closePath();
      openRoot(aCreate);
      if (iPath.size())
         iPathHandle = openHandle(iRootHandle, iPath, aCreate);
      else
         iPathHandle = iRootHandle;
      iPathReadOnly = !aCreate;
   } // if
} // openPath

void ZProfile::closePath()
{
   ZFUNCTRACE_DEVELOP("ZProfile::closePath()");
   if (iPathHandle) {
      if (iPathHandle != iRootHandle) closeHandle(iPathHandle);
      iPathHandle = 0;
   } // if
} // closePath

#endif // ZC_WIN

#ifdef ZC_WIN
void ZProfile::openRoot(ZBoolean aCreate)
{
   ZFUNCTRACE_DEVELOP("ZProfile::openRoot(ZBoolean aCreate)");
   if (iRootHandle == 0 || (aCreate && iRootReadOnly)) {
      closeRoot();
      HKEY parentKey(0);
      ZString path;
      while (!parentKey) {
         path = iRoot;
         ZString token(splitPath(path));
         for (unsigned i = 0; i < sizeof(sysHandles)/sizeof(SystemHandle); i++)
            if (token == sysHandles[i].iName) {
               parentKey = sysHandles[i].iHandle;
               break;
            } // if
         if (!parentKey)
            iRoot = ZString(sysHandles[0].iName)+(char)ZC_PATHSEPARATOR+iRoot;
      } // while
      if (path.length())
         iRootHandle = openHandle(parentKey, path, aCreate);
      else
         iRootHandle = parentKey;
      iRootReadOnly = !aCreate;
   } // if
} // openRoot
#endif

#ifdef ZC_OS2
void ZProfile::openRoot()
{
   ZFUNCTRACE_DEVELOP("ZProfile::openRoot()");
   if (iRootHandle == 0) {
      iRootHandle = PrfOpenProfile(iHab, iRoot);
      if (!iRootHandle)
         throwSysErr(PrfOpenProfileName);
   } // if
} // openRoot
#endif

void ZProfile::closeRoot()
{
   ZFUNCTRACE_DEVELOP("ZProfile::closeRoot()");
#ifdef ZC_WIN
   if (iRootHandle) {
      closePath();
      closeHandle(iRootHandle);
      iRootHandle = 0;
   } // if
#endif
#ifdef ZC_OS2
   if (iRootHandle != 0 &&
       iRootHandle != HINI_SYSTEMPROFILE &&
       iRootHandle != HINI_USERPROFILE) {
      if (!PrfCloseProfile(iRootHandle))
         throwSysErr(PrfCloseProfileName);
      iRootHandle = 0;
   } // if
#endif
} // closeRoot

ZExport0 ZProfile::ZProfile(const ZString& aRoot, const ZString& aPath)
{
   ZFUNCTRACE_DEVELOP("ZProfile::ZProfile(const ZString& aRoot, const ZString& aPath)");
   iRootHandle = 0;
#ifdef ZC_WIN
   iPathHandle = 0;
   iRoot = stripPath(aRoot);
   setPath(aPath);
#endif
#ifdef ZC_OS2
   iHab = WinInitialize(0);
   if (iHab == 0) throwSysErr(WinInitializeName);
   iRoot = aRoot;
   iPath = aPath;
#endif
} // ZProfile

ZExport0 ZProfile::ZProfile(const ZProfile& aProfile)
{
   ZFUNCTRACE_DEVELOP("ZProfile::ZProfile(const ZProfile& aProfile)");
   iRootHandle = 0;
#ifdef ZC_WIN
   iPathHandle = 0;
#endif
#ifdef ZC_OS2
   iHab = WinInitialize(0);
   if (iHab == 0) throwSysErr(WinInitializeName);
#endif
   *this = aProfile;
} // ZProfile

ZExport0 ZProfile::~ZProfile()
{
   ZFUNCTRACE_DEVELOP("ZProfile::~ZProfile()");
   closeRoot();
} // ~ZProfile

ZExport(ZProfile) ZProfile::systemProfile(const ZString& aPath)
{
   ZFUNCTRACE_DEVELOP("ZProfile::systemProfile(const ZString& aPath)");
#ifdef ZC_WIN
   return ZProfile(ZString(sysHandles[0].iName)+(char)ZC_PATHSEPARATOR+Software, aPath);
#endif
#ifdef ZC_OS2
   ZProfile prf("SystemProfile", aPath);
   prf.iRootHandle = HINI_SYSTEMPROFILE;
   return prf;
#endif
} // systemProfile

ZExport(ZProfile) ZProfile::userProfile(const ZString& aPath)
{
   ZFUNCTRACE_DEVELOP("ZProfile::userProfile(const ZString& aPath)");
#ifdef ZC_WIN
   return ZProfile(ZString(sysHandles[1].iName)+(char)ZC_PATHSEPARATOR+Software, aPath);
#endif
#ifdef ZC_OS2
   ZProfile prf("UserProfile", aPath);
   prf.iRootHandle = HINI_USERPROFILE;
   return prf;
#endif
} // userProfile

ZExport(ZProfile&) ZProfile::operator=(const ZProfile& aProfile)
{
   ZFUNCTRACE_DEVELOP("ZProfile::operator=(const ZProfile& aProfile)");
   closeRoot();
   iRoot = aProfile.iRoot;
   iPath = aProfile.iPath;
#ifdef ZC_OS2
   if (aProfile.iRootHandle == HINI_SYSTEMPROFILE ||
       aProfile.iRootHandle == HINI_USERPROFILE)
      iRootHandle = aProfile.iRootHandle;
#endif
   return *this;
} // operator=

ZExport(ZProfile&) ZProfile::setPath(const ZString& aPath)
{
   ZFUNCTRACE_DEVELOP("ZProfile::setPath(const ZString& aPath)");
#ifdef ZC_WIN
   ZString newPath(stripPath(aPath));
   if (iPath != newPath) {
      closePath();
      iPath = newPath;
   } // if
#endif
#ifdef ZC_OS2
   iPath = aPath;
#endif
   return *this;
} // setPath

ZExport(ZProfile&) ZProfile::getKeys(ZStringlist& aList)
{
   ZFUNCTRACE_DEVELOP("ZProfile::getKeys(ZStringlist& aList)");
   aList.drop();
#ifdef ZC_WIN
   openPath(zFalse);
   char buffer[MAX_PATH];
   long bufsize;
   for (unsigned long key = 0; ; key++) {
      bufsize = sizeof(buffer);
      if (RegEnumKeyEx(
             iPathHandle, key, buffer, (LPDWORD)&bufsize,
             NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
         break;
      aList.addAsLast(buffer);
   } // for
#endif
#ifdef ZC_OS2
   if (iPath.size()) return *this; // os/2 has no keys at this level

   openRoot();

   // get size of list (not including the terminating 0)
   ULONG size;
   if (!PrfQueryProfileSize(iRootHandle, 0, 0, &size))
      throwSysErr(PrfQueryProfileSizeName);

   if (size) {
      // allocate buffer
      ZString buf(0, size++);

      // read list of keys
      if (!PrfQueryProfileData(iRootHandle, 0, 0, buf, &size))
         throwSysErr(PrfQueryProfileDataName);

      // parse keys into stringlist
      char *s = buf;
      while (size) {
         ZString key;
         while (*s && size) { key += *s++; size--; }
         if (key.size()) aList.addAsLast(key);
         if (size) { s++; size--; }
      } // while
   } // if
#endif
   return *this;
} // getKeys

ZExport(ZProfile&) ZProfile::getValues(ZStringlist& aList)
{
   ZFUNCTRACE_DEVELOP("ZProfile::getValues(ZStringlist& aList)");
   aList.drop();
#ifdef ZC_WIN
   openPath(zFalse);
   char buffer[MAX_PATH];
   long bufsize;
   for (unsigned long key = 0; ; key++) {
      bufsize = sizeof(buffer);
      if (RegEnumValue(
             iPathHandle, key, buffer, (LPDWORD)&bufsize,
             NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
         break;
      aList.addAsLast(buffer);
   } // for
#endif
#ifdef ZC_OS2
   if (!iPath.size()) return *this; // os/2 has no values at this level

   openRoot();

   // get size of list (not including the terminating 0)
   unsigned long size;
   if (!PrfQueryProfileSize(iRootHandle, iPath, 0, &size))
      throwSysErr(PrfQueryProfileSizeName);

   if (size) {
      // create buffer
      ZString buf(0, size++);

      // read list of values
      if (!PrfQueryProfileData(iRootHandle, iPath, 0, buf, &size))
         throwSysErr(PrfQueryProfileDataName);

      // parse values into stringlist
      char *s = buf;
      while (size) {
         ZString key;
         while (*s && size) { key += *s++; size--; }
         if (key.size()) aList.addAsLast(key);
         if (size) { s++; size--; }
      } // while
   } // if
#endif
   return *this;
} // getValues

ZExport(ZBoolean) ZProfile::keyExists(const ZString& aKeyName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::keyExists(const ZString& aKeyName)");
   ZStringlist list;
   ZBoolean found;
   if (aKeyName.size()) {
      getKeys(list);
      found = list.find(aKeyName) >= 0;
   } else {
#ifdef ZC_WIN
      found = zTrue;
      try {
         openPath(zFalse);
      }
      catch (const ZException& exc) {
         found = zFalse;
      } // catch
#endif
#ifdef ZC_OS2
      ZString path(iPath);
      try {
         setPath("");
         getKeys(list);
         found = list.find(path) >= 0;
         setPath(path);
      } // try
      catch (const ZException& exc) {
         setPath(path);
         throw;
      } // catch
#endif
   } // if
   return found;
} // keyExists

ZExport(ZBoolean) ZProfile::valueExists(const ZString& aValueName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::valueExists(const ZString& aValueName)");
#ifdef ZC_WIN
   try {
      openPath(zFalse);
   }
   catch (const ZException& exc) {
      return zFalse;
   } // catch
#endif
#ifdef ZC_OS2
   openRoot();
#endif
   ZStringlist list;
   getValues(list);
   return list.find(aValueName) >= 0;
} // valueExists

ZExport(int) ZProfile::valueType(const ZString& aValueName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::valueType(const ZString& aValueName)");
#ifdef ZC_WIN
   openPath(zFalse);

   DWORD dataType;
   if (!RegQueryValueEx(
          iPathHandle, aValueName, 0,
          &dataType, NULL, NULL) == ERROR_SUCCESS)
      ZTHROWEXC(ValueNotFound);

   switch (dataType) {
      case 1: // String
      case 2: // ExpandString
         return String;
      case 3: // Binary
      case 7: // MultiString
         return Binary;
      case 4: // DWord
      case 5: // DWordBigEndian
         return Integer;
      default:;
   } // switch
   return Other;
#endif
#ifdef ZC_OS2
   ZString val(value(aValueName));
   if (ZString(val.asLong())==val) return Integer;
   if (val.isPrintable()) return String;
   return Binary;
#endif
} // valueType

ZExport(ZString) ZProfile::value(const ZString& aValueName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::value(const ZString& aValueName)");
#ifdef ZC_WIN
   openPath(zFalse);

   DWORD dataType, size;
   if (!RegQueryValueEx(
          iPathHandle, aValueName, 0,
          &dataType, NULL, &size) == ERROR_SUCCESS)
      ZTHROWEXC(ValueNotFound);

   if (size) {
      ZString str(0, size);
      RegQueryValueEx(
         iPathHandle, aValueName, 0,
         NULL, (LPBYTE)(char*)str, (LPDWORD)&size);

      switch (dataType) {
         case 1: // String
         case 2: // ExpandString
         case 7: // MultiString
            if (str.size()>0 && str[str.size()]==0)
               return str.subString(1,str.size());
         default:;
      } // switch
   } // if
#endif
#ifdef ZC_OS2
   if (!iPath.size()) ZTHROWEXC(MissingPath);
   if (!aValueName.size()) ZTHROWEXC(MissingValueName);
   openRoot();

   // query size of data
   unsigned long size;
   if (!PrfQueryProfileSize(iRootHandle, iPath, aValueName, &size))
      throwSysErr(PrfQueryProfileSizeName);

   if (size > 0) {
      ZString buf(0, size++);

      // try to get as string first
      PrfQueryProfileString(iRootHandle, iPath, aValueName, "", buf, size);
      ERRORID err = WinGetLastError(iHab);
      if (err == 0) {
         if (buf[buf.size()]==0 && buf.subString(1, buf.size()-1).isPrintable())
            return buf.subString(1,buf.size()-1);
         return buf;
      } // if

      if (ERRORIDERROR(err) != PMERR_INVALID_ASCIIZ)
         throwSysErr(PrfQueryProfileStringName);

      // try to get binary data
      if (!PrfQueryProfileData(iRootHandle, iPath, aValueName, buf, &size))
         throwSysErr(PrfQueryProfileDataName);
      return buf;
   } // if
#endif
   return ZString();
} // value

ZExport(long) ZProfile::longValue(const ZString& aValueName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::longValue(const ZString& aValueName)");
#ifdef ZC_WIN
   openPath(zFalse);

   DWORD data, dataType, size(4);
   if (!RegQueryValueEx(
          iPathHandle, aValueName, 0,
          &dataType, (LPBYTE)&data, &size) == ERROR_SUCCESS)
      ZTHROWEXC(ValueNotFound);

   if (dataType != 4) ZTHROWEXC(UnsupportedDataType);
   return data;
#endif
#ifdef ZC_OS2
   return value(aValueName).asLong();
#endif
} // longValue

ZExport(ZProfile&) ZProfile::setValue(const ZString& aValue, const ZString& aValueName, int aType)
{
   ZFUNCTRACE_DEVELOP("ZProfile::setValue(const ZString& aValue, const ZString& aValueName, int aType)");

   // find out type if auto
   if (aType == Auto) {
      ZString v(aValue);
      if (ZString(v.strip().asLong())==v)
         aType = Integer;
      else {
         if (aValue.isPrintable())
            aType = String;
         else
            aType = Binary;
      } // if
   } // if

#ifdef ZC_WIN
   long dataType;
   switch (aType) {
      case String:
         dataType = 1; // String
         break;
      case Integer:
         return setValue(aValue.asLong(), aValueName);
      default:
         dataType = 3; // Binary
   } // switch

   openPath(zTrue);

   if (valueExists(aValueName)) deleteValue(aValueName);

   if (!RegSetValueEx(
          iPathHandle, aValueName, 0,
          dataType, (LPBYTE)(const char*)aValue, aValue.size()) == ERROR_SUCCESS)
      throwSysErr(SRegSetValueEx);
#endif
#ifdef ZC_OS2
   if (!iPath.size()) ZTHROWEXC(MissingPath);
   if (!aValueName.size()) ZTHROWEXC(MissingValueName);
   openRoot();

   switch (aType) {
      case String:
         if (!PrfWriteProfileString(iRootHandle, iPath, aValueName,
                                    ZString::exp(aValue)))
            throwSysErr(PrfWriteProfileStringName);
         break;
      case Integer: {
         ZString v(aValue);
         if (!PrfWriteProfileString(iRootHandle, iPath, aValueName,
                                    ZString(v.strip().asLong())))
            throwSysErr(PrfWriteProfileStringName);
         break;
      } // Integer
      default: {
         ZString val(aValue);
         if (!PrfWriteProfileData(iRootHandle, iPath, aValueName,
                                  (char*)val, val.size()))
            throwSysErr(PrfWriteProfileDataName);
      } // default
   } // switch
#endif
   return *this;
} // setValue

ZExport(ZProfile&) ZProfile::setValue(long aValue, const ZString& aValueName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::setValue(const ZString& aValue, const ZString& aValueName, int aType)");
#ifdef ZC_WIN
   openPath(zTrue);

   if (valueExists(aValueName)) deleteValue(aValueName);

   if (!RegSetValueEx(
          iPathHandle, aValueName, 0,
          4, (LPBYTE)&aValue, 4) == ERROR_SUCCESS)
      throwSysErr(SRegSetValueEx);
#endif
#ifdef ZC_OS2
   setValue(ZString(aValue));
#endif
   return *this;
} // setValue

ZExport(ZProfile&) ZProfile::deleteValue(const ZString& aValueName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::deleteValue(const ZString& aValueName)");
#ifdef ZC_WIN
   openPath(zFalse);
   RegDeleteValue(iPathHandle, aValueName);
#endif
#ifdef ZC_OS2
   if (!iPath.size()) ZTHROWEXC(MissingPath);
   if (!aValueName.size()) ZTHROWEXC(MissingValueName);
   openRoot();
   if (!PrfWriteProfileString(iRootHandle, iPath, aValueName, 0))
      throwSysErr(PrfWriteProfileStringName);
#endif
   return *this;
} // deleteValue

ZExport(ZProfile&) ZProfile::deleteKey(const ZString& aKeyName)
{
   ZFUNCTRACE_DEVELOP("ZProfile::deleteKey(const ZString& aKeyName)");
#ifdef ZC_WIN
   // delete all values and subkeys first
   ZString oldPath(iPath);
   try {
      setPath(iPath+(char)ZC_PATHSEPARATOR+aKeyName);
      openPath(zFalse);

      ZStringlist list;
      int i;

      // delete all values
      setValue(ZString()); // just clear out default value
      getValues(list);
      for (i = 0; i < list.count(); i++)
         if (list[i].size()) {
            deleteValue(list[i]);
         } // if

      // delete all subkeys
      getKeys(list);
      for (i = 0; i < list.count(); i++)
         deleteKey(list[i]);
   } // try
   catch (const ZException& exc) {
      setPath(oldPath);
      throw;
   } // catch

   setPath(oldPath);
   openPath(zFalse);
   RegDeleteKey(iPathHandle, aKeyName);
#endif
#ifdef ZC_OS2
   if (iPath.size() && aKeyName.size()) return *this; // no keys at this level

   openRoot();

   if (!iPath.size() && !aKeyName.size()) {
      // delete all applications:

      // will only do this if not the system- or user profile!
      if (iRootHandle == HINI_SYSTEMPROFILE ||
          iRootHandle == HINI_USERPROFILE) return *this;

      ZStringlist apps;
      getKeys(apps);
      for (long i = 0; i < apps.count(); i++)
         if (!PrfWriteProfileString(iRootHandle, apps[i], 0, 0))
            throwSysErr(PrfWriteProfileStringName);
   } else {
      if (!PrfWriteProfileString(
           iRootHandle,
           iPath.size() ? iPath : aKeyName,
           0, 0))
         throwSysErr(PrfWriteProfileStringName);
   } // if
#endif
   return *this;
} // deleteKey
